/*
Script: Fx.Base.js
	Contains <Fx.Base>, the foundamentals of the MooTools Effects.

License:
	MIT-style license.
*/

var Fx = {};
var fx = Fx;

//basic class implementation

var Klass = function(hash){
	var klass = function(){
		return (this.initialize) ? this.initialize.apply(this, arguments) : this;
	};
	return Object.extend(klass, {'copy': this.copy, 'prototype': hash});
};

Klass.prototype.copy = function(hash){
	return new Klass(Object.extend(Object.extend({}, this.prototype), hash));
};

/*
Class: Fx.Base
	Base class for the Effects.

Options:
	transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.Sine.easeInOut>
	duration - the duration of the effect in ms; 500 is the default.
	unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
	wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
	fps - the frames per second for the transition; default is 50
	onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
	onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
	onCancel - the function to execute when you manually stop the effect.
*/

Fx.Base = new Klass({

	getOptions: function(){
		return {
			onStart: new Function,
			onComplete: new Function,
			onCancel: new Function,
			transition: function(p){
				return -(Math.cos(Math.PI * p) - 1) / 2;
			},
			duration: 500,
			unit: 'px',
			wait: true,
			fps: 50
		};
	},

	_initialize: function(element, options){
		this.element = $(element);
		this.options = Object.extend(this.getOptions(), options);
	},

	step: function(){
		var time = new Date().getTime();
		if (time < this.time + this.options.duration){
			this.delta = this.options.transition((time - this.time) / this.options.duration);
			this.setNow();
			this.increase();
		} else {
			this.stop(true);
			this.set(this.to);
			this.options.onComplete.call(this, this.element);
		}
	},

	_set: function(to){
		this.now = to;
		this.increase();
		return this;
	},

	_setNow: function(){
		this.now = this.compute(this.from, this.to);
	},

	compute: function(from, to){
		return (to - from) * this.delta + from;
	},

	_start: function(from, to){
		if (!this.options.wait) this.stop();
		else if (this.timer) return this;
		this.from = from;
		this.to = to;
		this.change = this.to - this.from;
		this.time = new Date().getTime();
		this.timer = setInterval(this.step.bind(this), Math.round(1000 / this.options.fps));
		this.options.onStart.call(this, this.element);
		return this;
	},
	
	/*
	Property: stop
		Stops the transition.
	*/

	stop: function(end){
		if (!this.timer) return this;
		this.timer = clearInterval(this.timer);
		this.timer = null;
		if (!end) this.options.onCancel.call(this, this.element);
		return this;
	}

});